package com.sgy.util;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.List;

public class RedisUtil {
    private static Logger log= LoggerFactory.getLogger(RedisUtil.class);
    private RedisUtil(){

    }
    @Value("${spring.redis.host}")
    private static String ADDR;
    @Value("${spring.redis.port}")
    private static int PORT;
    @Value("${spring.redis.password}")
    private static String AUTH;

    //可用连接实例的最大数目，默认值为8；
    //如果赋值为-1，则表示不限制，如果pool已经分配了maxActive个jedis实例，则此时pool的状态为exhausted(耗尽)
    private static int MAX_ACTIVE = -1;
    //控制一个pool最多有多少个状态为idle(空闲)的jedis实例，默认值是8
    private static int MAX_IDLE = 300;
    //等待可用连接的最大时间，单位毫秒，默认值为-1，表示永不超时，如果超过等待时间，则直接抛出JedisConnectionException
    private static int MAX_WAIT = -1;
    //超时时间
    private static int TIMEOUT = 1000*5;
    //在borrow一个jedis实例时，是否提前进行validate操作；如果为true，则得到的jedis实例均是可用的；
    private static boolean TEST_ON_BORROW = true;

    private static JedisPool jedisPool;

    /**
     * redis过期时间,以秒为单位
     */
    public final static int EXRP_HOUR = 60 * 60;          //一小时
    public final static int EXRP_DAY = 60 * 60 * 24;        //一天
    public final static int EXRP_MONTH = 60 * 60 * 24 * 30;   //一个月

    /**
     * 初始化Redis连接池，注意一定要在使用前初始化一次，一般在项目启动时初始化就行了
     * @return
     */
    public static JedisPool initialPool(){
        JedisPool jp=null;
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxTotal(MAX_ACTIVE);
            config.setMaxIdle(MAX_IDLE);
            config.setMaxWaitMillis(MAX_WAIT);
            config.setTestOnBorrow(TEST_ON_BORROW);
            config.setTestOnCreate(true);
            config.setTestWhileIdle(true);
            config.setTestOnReturn(true);
            config.setNumTestsPerEvictionRun(-1);
            jp = new JedisPool(config,ADDR,PORT,TIMEOUT,AUTH);
            jedisPool = jp;
        } catch (Exception e) {
            log.error("redis服务器异常",e);
        }
        return jp;
    }

    public static void close(Jedis jedis){
        jedis.close();
    }

    /**
     * 在多线程环境同步初始化
     */
    private static synchronized void poolInit(){
        if(jedisPool == null){
            initialPool();
        }
    }

    /**
     * 获取Jedis实例，一定先初始化
     */
    public static Jedis getJedis(){
        boolean success = false;
        Jedis jedis = null;
        if(jedisPool == null){
            poolInit();
        }
        int i=0;
        while (!success){
            i++;
            try {
                if(jedisPool!=null){
                    jedis = jedisPool.getResource();
                }else {
                    throw new RuntimeException("Redis连接池初始化失败");
                }
            } catch (RuntimeException e) {
                log.info(Thread.currentThread().getName()+":第"+i+"次获取失败！！！");
                success = false;
                log.error("Redis服务器异常",e);
            }
            if(jedis!=null){
                success=true;
            }
            if(i>=10&&i<20){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                }
            }

            if (i>=20&&i<30){
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {

                }
            }

            if (i>=30&&i<40){
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {

                }
            }

            if (i>=40){
                log.error("redis彻底连不上了~~~~(>_<)~~~~");
                return null;
            }
        }
        return jedis;
    }

    /**
     * 设置String
     * @param key
     * @param value
     */
    public static void setString(String key,String value){
        Jedis jedis = null;
        try {
            value = StringUtils.isBlank(value) ? "" : value;
            jedis = getJedis();
            jedis.set(key,value);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis服务器异常");
        } finally {
            if(jedis != null){
                close(jedis);
            }
        }
    }

    /**
     * 设置过期时间
     * @param key
     * @param seconds
     * @param value
     */
    public static void setString(String key,int seconds,String value){
        Jedis jedis = null;
        try {
            value = StringUtils.isBlank(value) ? "" : value;
            jedis = getJedis();
            jedis.setex(key,seconds,value);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis服务器异常");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    /**
     * 获取String值
     * @param key
     * @return
     */
    public static String getString(String key){
        Jedis jedis=null;
        try {
            jedis=getJedis();
            if(jedis==null || !jedis.exists(key)){
                return null;
            }
            return jedis.get(key);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    public static long incrBy(String key,long integer){
        Jedis jedis = null;
        try {
            jedis=getJedis();
            return jedis.incrBy(key,integer);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    public static long decrBy(String key,long integer){
        Jedis jedis = null;
        try {
            jedis=getJedis();
            return jedis.decrBy(key,integer);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    //删除多个key
    public static long delKeys(String[] keys){
        Jedis jedis=null;
        try {
            jedis=getJedis();
            return jedis.del(keys);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    //删除单个key
    public static long delKey(String key){
        Jedis jedis=null;
        try {
            jedis=getJedis();
            return jedis.del(key);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    //添加到队列尾
    public static long rpush(String key,String node){
        Jedis jedis=null;
        try {
            jedis=getJedis();
            return jedis.rpush(key,node);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    //删除List元素
    public static long delListNode(String key,int count,String value){
        Jedis jedis=null;
        try {
            jedis=getJedis();
            return jedis.lrem(key,count,value);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
    }

    //获取所有List
    public static List getListAll(String key){
        Jedis jedis=null;
        List list = null;
        try {
            jedis=getJedis();
            list=jedis.lrange(key,0,-1);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
        return list;
    }

    /**
     *
     * @param key   hash
     * @param fieldKey 字段
     * @param fieldV  字段值
     * @return
     */
    public static Long hset(String key,String fieldKey,String fieldV){
        Jedis jedis=null;
        Long r;
        try {
            jedis=getJedis();
            r=jedis.hset(key,fieldKey,fieldV);
        } catch (Exception e) {
            log.error("Redis服务器异常",e);
            throw new RuntimeException("Redis操作错误");
        } finally {
            if(jedis!=null){
                close(jedis);
            }
        }
        return r;
    }

    /**
     *
     * @param key :hashkey
     * @param fieldKey 字段
     *
     */

    public static  String hget(String key,String fieldKey){
        Jedis jedis = null;
        String r;
        try {
            jedis = getJedis();
            r=jedis.hget(key,fieldKey);
        } catch (Exception e) {
            log.error("redis服务器异常",e);
            throw new  RuntimeException("redis操作错误");
        } finally {
            if (jedis != null) {
                close(jedis);
            }
        }

        return  r;
    };


    /**
     *
     * @param key :hashkey
     * @param fieldKey 字段
     *
     */

    public static  Long hdel(String key,String fieldKey){
        Jedis jedis = null;
        Long r;
        try {
            jedis = getJedis();
            r=   jedis.hdel(key,fieldKey);
        } catch (Exception e) {
            log.error("redis服务器异常",e);
            throw new  RuntimeException("redis操作错误");
        } finally {
            if (jedis != null) {
                close(jedis);
            }
        }

        return  r;
    };

    //清理缓存redis
    public static void cleanLoacl(Jedis jedis){
        close(jedis);
    }
    static {
        initialPool();
    }

}
